import tkinter as tk
from tkinter import ttk
from threading import Thread, Event
import queue
from stepper import MotorController
from proximity_sensor import ProximitySensor
import logging
from create_tool_tip import createToolTip
from tkinter import scrolledtext # 2
from tkinter import Menu
from tkinter import messagebox as mBox
from tkinter import PhotoImage
import time


# 丝杆型号1605；16：丝杆直径；05：螺距，丝杆导程，电机转一圈移动的直线距离，即电机转360度，移动5mm
kPITCH = 5
kSPR = 1600
CW = True   # 顺时针方向
CCW = False # 逆时针方向
class MainApplication(tk.Tk):
    def __init__(self):
        super().__init__()

        self.stop_event_sensor = Event()  # 用于停止线程
        self.isforward_cliked = False # 是否为点击了前进
        self.isbackward_cliked = False	 # 是否点击了后退

        self.title("Extrusion control interface")
        self.geometry("600x600")
        self.protocol("WM_DELETE_WINDOW", self.safe_shutdown)
        
        # 创建停止事件和状态队列
        self.stop_event = Event()
        self.status_queue = queue.Queue()
        icon_img = PhotoImage(file=r'./favicon.png')
        self.iconphoto(True,icon_img)
        # 设置UI
        # self.setup_ui()
        self.createWidget()


        self.rotate = 1 #圈数
        self.forward_degrees = 180 #角度
        self.back_degrees = 180 #角度
        self.delay_fast = 0.0002  #快速
        self.delay_low = 0.002  #慢速
        self.motor = MotorController(self.stop_event, self.status_queue)

        # 启动传感器工作线程
        self.start_workers()
        # 启动UI更新循环
        self.after(100, self.update_ui)



    def clickMe(self): # 2
        speed_str = self.numberChosen0.get()
        distance_str = self.nameEntered0.get().strip()
        speed_str_back = self.numberChosen1.get()
        distance_str_back = self.nameEntered1.get().strip()
        print("distance_str 原始值:", distance_str, "类型:", type(distance_str))
        print("speed_str 原始值:", speed_str, "类型:", type(speed_str))
        print("distance_str_back 原始值:", distance_str_back, "类型:", type(distance_str_back))
        print("speed_str_back 原始值:", speed_str_back, "类型:", type(speed_str_back))
        # 检查角度输入是否为空或无效
        if not (distance_str or speed_str):
            mBox.showerror("错误", "请输入柱塞前进距离(mm)并选择运动速度!")
            return
        try:
            distance = float(distance_str)
            speed = float(speed_str)
            print("distance_str 转换后值:", distance, "类型:", type(distance))
            print("speed_str 转换后值:", speed, "类型:", type(speed))
            # 输入正常时弹窗显示参数
            mBox.showinfo("参数确认", f"速度: {speed} mm/s\n距离: {distance} mm")
        except ValueError:
            mBox.showerror("错误", "请输入有效的数字！")
            return
        # self.action.configure(text='前进到头 ' + self.name.get()+ ' ' +self.numberChosen.get())

        # self.numberChosen.configure(state='disable')
        # self.nameEntered0.configure(state='disable')
        # self.nameEntered1.configure(state='disable')

    def validate_float_input(input_str, field_name):
        """验证输入是否为有效的浮点数"""
        input_str = input_str.strip()
        if not input_str:
            return None, f"{field_name}不能为空"
        
        # 检查是否包含非法字符
        if not re.match(r'^[-+]?[0-9]*\.?[0-9]+$', input_str):
            return None, f"{field_name}必须是有效的数字"
        
        try:
            return float(input_str), None
        except ValueError:
            return None, f"{field_name}必须是有效的数字"



    def _update_button_states(self):
        """更新按钮显示状态"""
        if self.motor.running:
            if self.isforward_clicked:
                self.action3.configure(text='前进中')
                self.action2.configure(text='后退一次')  # 另一个按钮恢复原样
            elif self.isbackward_clicked:
                self.action2.configure(text='后退中')
                self.action3.configure(text='前进一次')  # 另一个按钮恢复原样
        else:
            # 电机停止运行时，两个按钮都显示"一次"
            self.action3.configure(text='前进一次')
            self.action2.configure(text='后退一次')
            # 重置点击状态
            self.isforward_clicked = False
            self.isbackward_clicked = False



    def forward_motion(self): # 2
        """按钮点击事件：给电机发送前进消息"""
        # self.action3.configure(text='前进中 ' + self.name.get()+ ' ' +self.numberChosen.get())
        if self.motor.is_low_limit:
            mBox.showwarning("警告", "已到达前进限位,无法前进！")
            # self.action3.config(state=tk.DISABLED, text="触发限位")
            self.log_text.insert(tk.END, "已到达前进限位,无法前进！\n")
            self.motor.pause()
            return
        # 设置前进状态
        self.isforward_clicked = True
        self.isbackward_clicked = False
        # 更新按钮状态
        self._update_button_states()
        #self.action3.configure(text='前进中')
    
        print("forward_motion")
        self.log_text.insert(tk.END, "forward_motion...\n")
        speed_str = self.numberChosen0.get()
        distance_str = self.nameEntered0.get().strip()
        
        # 获取角度
        print("distance_str is:", distance_str)
        print("speed_str is:", speed_str)
        try:
            distance_cmd = float(distance_str)
            speed_cmd = float(speed_str)
        except ValueError:
            print("输入格式错误，请输入有效的数字")
            self.log_text.insert(tk.END, "错误：请输入有效的数字\n")

        # 计算脉冲数和延迟
        speed = 1  #如果为1,等于50 mm/s   #speed = 1687500 毫米
        speed = speed_cmd
        rotate_per_s = speed/kPITCH  # ex. rotate_per_s = 0.2
        degree_per_s = 360 * rotate_per_s # ex. degree_per_s = 72
        plus = degree_per_s/(360/kSPR) #ex.   plus = 320
        delay = 1/plus  #ex.delay = 0.003125  #0.0002(比较快)
        print("forward_motion delay :", delay)
        # self.log_text.insert(tk.END, "forward_motion delay :", delay, "\n")
        # self.log_text.insert(tk.END, "前进运动脉冲间隔为 :", str(delay), "\n")
        self.log_text.insert(tk.END, "forward_motion interval: {:.2f}\n".format(delay))
        self.log_text.insert(tk.END, "forward_motion speed: {}\n".format(speed_str))
        self.log_text.see(tk.END)  # 滚动到底部，实时查看日志

        # 计算步数
        distance = 5 # 如果为5 mm,刚好一圈
        distance = distance_cmd
        degree = (360/5)*distance # 旋转360度，等于直线移动5mm
        steps = int((abs(degree) / 360.0) * kSPR)
        direction = True  # True 为顺时针方向
        
        # 传递电机参数
        self.motor.set_parameters(steps=steps, delay=delay, direction=direction)
        self.stop_event.clear()
    def backward_motion(self): # 2

        #依据限位执行动作
        if self.motor.is_upper_limit:
            mBox.showwarning("警告", "已到达后退限位，无法后退！")
            # self.action2.config(state=tk.DISABLED, text="触发限位")
            self.log_text.insert(tk.END, "已到达后退限位,无法后退！\n")
            self.motor.pause()
            return

        # self.action2.configure(text='后退中')
        print("backward_motion")
        self.log_text.insert(tk.END, "backward_motion...\n")
        # 设置后退状态
        self.isforward_clicked = False
        self.isbackward_clicked = True
        # 更新按钮状态
        self._update_button_states()

        speed_str = self.numberChosen1.get()
        distance_str = self.nameEntered1.get().strip()
        # 获取角度
        print("distance_str_back is:", distance_str)
        print("speed_str_back is:", speed_str)
        try:
            distance_cmd = float(distance_str)
            speed_cmd = float(speed_str)
        except ValueError:
            print("输入格式错误，请输入有效的数字")
            self.log_text.insert(tk.END, "错误：请输入有效的数字\n")        

        # 计算脉冲数和延迟
        speed = 1  #如果为1,等于50 mm/s   #speed = 1687500 毫米
        speed = speed_cmd
        rotate_per_s = speed/kPITCH  # ex. rotate_per_s = 0.2
        degree_per_s = 360 * rotate_per_s # ex. degree_per_s = 72
        plus = degree_per_s/(360/kSPR) #ex.   plus = 320
        delay = 1/plus  #ex.delay = 0.003125  #0.0002(比较快)
        print("backward_motion delay :", delay)
        # self.log_text.insert(tk.END, "backward_motion delay :", delay, "\n")
        self.log_text.insert(tk.END, "back_motion interval: {:.2f}\n".format(delay))
        self.log_text.insert(tk.END, "back_motion speed: {}\n".format(speed_str))

        # 计算步数
        distance = 5 # 如果为5 mm,刚好一圈
        distance = distance_cmd
        degree = (360/5)*distance # 旋转360度，等于直线移动5mm
        steps = int((abs(degree) / 360.0) * kSPR)
        direction = False  # True 为逆时针方向
        
        # 传递电机参数
        self.motor.set_parameters(steps=steps, delay=delay, direction=direction)
        self.stop_event.clear()
        # self.action.configure(text='Hello ' + self.name.get()+ ' ' +self.numberChosen.get())
        # self.direction = Sign.BACK
        # self.motor.move_degrees(degrees=self.direction*self.back_degrees, delay=self.delay_fast)
        # self.numberChosen.configure(state='disable')
        # self.nameEntered.configure(state='disable')       
    def backward_limit(self): # 2
        # self.action.configure(text='Hello ' + self.name.get()+ ' ' +self.numberChosen.get())
        #出发限位，报警弹窗，依据限位执行动作
        if self.motor.is_upper_limit:
            mBox.showwarning("警告", "已到达后退限位，无法后退！")
            # self.action2.config(state=tk.DISABLED, text="触发限位")
            self.log_text.insert(tk.END, "已到达后退限位，无法后退！ \n")
            self.motor.pause()
            return

        print("backward_limit_motion")
        # self.log_text.insert(tk.END, "forward_limit_motion! \n")
        self.log_text.insert(tk.END, "back_motion interval: {:.2f}\n".format(delay))
        self.log_text.insert(tk.END, "back_motion speed: {}\n".format(speed_str))
        speed_str = self.numberChosen1.get()
        # 获取角度
        print("speed_str_back is:", speed_str)
        try:
            speed_cmd = float(speed_str)
        except ValueError:
            print("输入格式错误，请输入有效的数字")
            self.log_text.insert(tk.END, "错误：请输入有效的数字\n")   
        # 计算脉冲数和延迟
        speed = 1  #如果为1,等于50 mm/s   #speed = 1687500 毫米
        speed = speed_cmd
        rotate_per_s = speed/kPITCH  # ex. rotate_per_s = 0.2
        degree_per_s = 360 * rotate_per_s # ex. degree_per_s = 72
        plus = degree_per_s/(360/kSPR) #ex.   plus = 320
        delay = 1/plus  #ex.delay = 0.003125  #0.0002(比较快)
        print("backward_motion delay :", delay)
        self.log_text.insert(tk.END, "backward_motion delay :", delay, "\n")

        # 计算步数
        distance_cmd = 200 # 如果为5 mm,刚好一圈
        distance = distance_cmd
        degree = (360/5)*distance # 旋转360度，等于直线移动5mm
        steps = int((abs(degree) / 360.0) * kSPR)
        direction = False  # True 为逆时针方向
        
        # 传递电机参数
        self.motor.set_parameters(steps=steps, delay=delay, direction=direction)
        self.stop_event.clear()
        # self.numberChosen.configure(state='disable')
        # self.nameEntered.configure(state='disable')    
    def forward_limit(self): # 2
        # 功能，会改变按钮显示的字
        #self.action.configure(text='Hello ' + self.name.get()+ ' ' +self.numberChosen.get())
        if self.motor.is_low_limit:
            mBox.showwarning("警告", "已到达前进限位,无法前进！")
            # self.action3.config(state=tk.DISABLED, text="触发限位")
            self.log_text.insert(tk.END, "已到达前进限位,无法前进！\n")
            self.motor.pause()
            return

        speed_str = self.numberChosen0.get()
        # 获取角度
        print("speed_str is:", speed_str)
        try:
            speed_cmd = float(speed_str)
        except ValueError:
            print("输入格式错误，请输入有效的数字")
            self.log_text.insert(tk.END, "错误：请输入有效的数字\n")
        # 计算脉冲数和延迟
        speed = 1  #如果为1,等于50 mm/s   #speed = 1687500 毫米
        speed = speed_cmd
        rotate_per_s = speed/kPITCH  # ex. rotate_per_s = 0.2
        degree_per_s = 360 * rotate_per_s # ex. degree_per_s = 72
        plus = degree_per_s/(360/kSPR) #ex.   plus = 320
        delay = 1/plus  #ex.delay = 0.003125  #0.0002(比较快)
        print("forward_motion delay :", delay)
        # self.log_text.insert(tk.END, "forward_motion delay :", delay, "\n")
        self.log_text.insert(tk.END, "forward_motion interval: {:.2f}\n".format(delay))
        self.log_text.insert(tk.END, "forward_motion speed: {}\n".format(speed_str))
        print("forward_limit_motion")
        self.log_text.insert(tk.END, "forward_limit...\n")


        #计算steps步数,给一个很大的数,20cm
        distance_cmd = 200 
        distance = distance_cmd
        degree = (360/5)*distance # 旋转360度，等于直线移动5mm
        steps = int((abs(degree) / 360.0) * kSPR)
        direction = True  # True 为顺时针方向

        # 传递电机参数
        self.motor.set_parameters(steps=steps, delay=delay, direction=direction)
        self.stop_event.clear()
        # self.numberChosen.configure(state='disable')
        # self.nameEntered.configure(state='disable')    
    def createWidget(self):
        tabControl = ttk.Notebook(self) # Create Tab Control---------------
        self.tab1 = ttk.Frame(tabControl) # Create a tab 
        tabControl.add(self.tab1, text='Tab 1') # Add the tab--------------

        self.tab2 = ttk.Frame(tabControl) # Create a tab 
        tabControl.add(self.tab2, text='Tab 2') # Add the tab

        self.tab3 = ttk.Frame(tabControl) # Add a third tab
        tabControl.add(self.tab3, text='Tab 3') # Make second tab visible

        self.monty = ttk.LabelFrame(self.tab1, text=' 参数设置 ')
        self.monty.grid(column=1, row=5,padx=10,pady=10)

        self.monty1 = ttk.LabelFrame(self.tab2, text=' monty1 ')
        self.monty1.grid(column=1, row=0,padx=10,pady=10)

        # Tab Control 3 -------------------------------
        self.tab3 = tk.Frame(self.tab3, bg='blue')
        self.tab3.pack()
        for orangeColor in range(2):
            canvas = tk.Canvas(self.tab3, width=150, height=80, highlightthickness=0, bg='orange')
            canvas.grid(row=orangeColor, column=orangeColor)
        self.action0 = ttk.Button(self.monty, text="确认",command=self.clickMe)
        # Modified Button Click Function # 1
        # Position Button in second row, second column (zero-based)
        self.action0.grid(column=4, row=1)

        self.action1 = ttk.Button(self.monty, text="后退到底",command=self.backward_limit)
        # Modified Button Click Function # 1
        # Position Button in second row, second column (zero-based)
        self.action1.grid(column=0, row=4)
        self.action2 = ttk.Button(self.monty, text="后退一次",command=self.backward_motion)
        # Modified Button Click Function # 1
        # Position Button in second row, second column (zero-based)
        self.action2.grid(column=1, row=4)
        self.action3 = ttk.Button(self.monty, text="前进一次",command=self.forward_motion)
        # Modified Button Click Function # 1
        # Position Button in second row, second column (zero-based)
        self.action3.grid(column=2, row=4)
        self.action4 = ttk.Button(self.monty, text="前进到头",command=self.forward_limit)
        # Modified Button Click Function # 1
        # Position Button in second row, second column (zero-based)
        self.action4.grid(column=3, row=4)
        self.action5 = ttk.Button(self.monty, text="停止运动", command=self.safe_pause_motor)
        # Modified Button Click Function # 1
        # Position Button in second row, second column (zero-based)
        self.action5.grid(column=4, row=7, padx=0)



        # # Changing our Label # 3
        # ttk.Label(self.monty, text="柱塞前进距离\n(mm):").grid(column=0, row=0) # 4
        # # Adding a Textbox Entry widget # 5
        # number0 = tk.StringVar(value="5") # 默认值为 5
        # self.nameEntered0 = ttk.Entry(self.monty, width=12,textvariable=number0) # 7
        # # self.nameEntered0.insert(0, "5")  # 直接插入默认值（即使 textvariable 已设置）
        # self.nameEntered0.bind("<FocusIn>", lambda e: self.nameEntered0.select_range(0, tk.END))  # 选中默认值以便用户直接修改
        # self.nameEntered0.grid(column=0, row=1) # 8
        # self.nameEntered0.focus()   #将鼠标光标定位在此中# Place cursor into name Entry

        ttk.Label(self.monty, text="柱塞前进距离\n(mm):").grid(column=2, row=0) # 1
        number0 = tk.StringVar(value="5") # 2 设置默认值为1
        self.nameEntered0 = ttk.Combobox(self.monty, width=12, textvariable=number0, values=("5", "10", "15", "20", "3", "1")) #3#可以直接作为元组传入
        # self.numberChosen.configure(state='readonly')# 不允许允许用户手动输入数值，只读
        self.nameEntered0.grid(column=2, row=1) 


        ttk.Label(self.monty, text="前进速度\n(mm/s):").grid(column=3, row=0) # 1
        numberC0 = tk.StringVar(value="0.5") # 2 设置默认值为1
        self.numberChosen0 = ttk.Combobox(self.monty, width=12, textvariable=numberC0, values=("0.5", "0.8", "1.0", "1.5", "0.1", "0.2")) #3#可以直接作为元组传入
        # self.numberChosen.configure(state='readonly')# 不允许允许用户手动输入数值，只读
        self.numberChosen0.grid(column=3, row=1) # 5



        # ttk.Label(self.monty, text="柱塞后退距离\n(mm):").grid(column=2, row=0) # 4
        # # Adding a Textbox Entry widget # 5
        # number1 = tk.StringVar(value="5") # 默认值为 5
        # self.nameEntered1 = ttk.Entry(self.monty, width=12,textvariable=number1) # 7
        # # self.nameEntered0.insert(0, "5")  # 直接插入默认值（即使 textvariable 已设置）
        # self.nameEntered1.bind("<FocusIn>", lambda e: self.nameEntered0.select_range(0, tk.END))  # 选中默认值以便用户直接修改
        # self.nameEntered1.grid(column=2, row=1) # 8
        # self.nameEntered1.focus()   #将鼠标光标定位在此中# Place cursor into name Entry

        ttk.Label(self.monty, text="柱塞后退距离\n(mm):").grid(column=0, row=0) # 1
        number1 = tk.StringVar(value="5") # 2 设置默认值为1
        self.nameEntered1 = ttk.Combobox(self.monty, width=12, textvariable=number1, values=("5", "10", "15", "20", "3", "1")) #3#可以直接作为元组传入
        # self.numberChosen.configure(state='readonly')# 不允许允许用户手动输入数值，只读
        self.nameEntered1.grid(column=0, row=1) 



        ttk.Label(self.monty, text="后退速度\n(mm/s):").grid(column=1, row=0) # 1
        numberC1 = tk.StringVar(value="1.0") # 2 设置默认值为1
        self.numberChosen1 = ttk.Combobox(self.monty, width=12, textvariable=numberC1, values=( "1.0", "1.5", "0.1", "0.2","0.5", "0.8",)) #3#可以直接作为元组传入
        # self.numberChosen.configure(state='readonly')# 不允许允许用户手动输入数值，只读
        self.numberChosen1.grid(column=1, row=1) # 5



        # ttk.Label(self.monty, text="电机旋转角度\n(deg)").grid(column=1, row=0) # 4
        # # Adding a Textbox Entry widget # 5
        # self.name = tk.StringVar() # 6
        # self.nameEntered1 = ttk.Entry(self.monty, width=12,textvariable=self.name) # 7
        # self.nameEntered1.grid(column=1, row=1) # 8
        # self.nameEntered1.focus()   #将鼠标光标定位在此中# Place cursor into name Entry

        # Creating three checkbuttons # 1
        # chVarDis = tk.IntVar() # 2
        # check1 = tk.Checkbutton(self.monty1, text="Disabled", variable=chVarDis, state='disabled') # 3
        # check1.select() # 4
        # check1.grid(column=0, row=4, sticky=tk.W) # 5 #west east tk.W左对齐，tk.E右对齐
        # chVarUn = tk.IntVar() # 6
        # check2 = tk.Checkbutton(self.monty1, text="UnChecked", variable=chVarUn)
        # check2.deselect() # 8
        # check2.grid(column=1, row=4, sticky=tk.W) # 9 
        # chVarEn = tk.IntVar() # 10
        # check3 = tk.Checkbutton(self.monty1, text="Enabled", variable=chVarEn)
        # check3.select() # 12
        # check3.grid(column=2, row=4, sticky=tk.W) # 13

        # Radiobutton Globals # 1
        # COLOR1 = "Blue" # 2
        # COLOR2 = "Gold" # 3
        # COLOR3 = "Red" # 4
        # Radiobutton Callback # 5
        # def radCall(): # 6
        #     radSel=radVar.get()
        #     if radSel == 1: self.monty1.configure(text=COLOR1)
        #     elif radSel == 2: self.monty1.configure(text=COLOR2)
        #     elif radSel == 3: self.monty1.configure(text=COLOR3)
        # create three Radiobuttons # 7
        # radVar = tk.IntVar() # 8
        # #radVar1 = tk.IntVar() # 8
        # rad1 = tk.Radiobutton(self.monty1, text=COLOR1, variable=radVar, value=1, command=radCall) # 9
        # rad1.grid(column=0, row=4, sticky=tk.W) # 10
        # rad2 = tk.Radiobutton(self.monty1, text=COLOR2, variable=radVar, value=2, command=radCall) # 11
        # rad2.grid(column=1, row=4, sticky=tk.W) # 12
        # rad3 = tk.Radiobutton(self.monty1, text=COLOR3, variable=radVar, value=3, command=radCall) # 13
        # rad3.grid(column=2, row=4, sticky=tk.W) # 14

        # def _spin():
        #     value = spin.get()
        #     print(value)
        #     scr.insert(tk.INSERT, value + '\n')
        # Adding a Spinbox widget
        # spin =ttk.Spinbox(self.monty, from_=0, to=10,width=5,command=_spin)
        # spin1 =ttk.Spinbox(self.monty, values=(1,3,5,7,8),width=5,command=_spin)
        # spin.grid(column=0, row=4)
        # spin1.grid(column=4, row=4)

        # createToolTip(spin, 'This is a Spin control.')
        # createToolTip(spin1, 'This is a Spin control1.')
        # Add this import to the top of the Python Module # 1
        #from tkinter import scrolledtext # 2
        # # Using a scrolled Text control # 3
        # scrolW = 30 # 4
        # scrolH = 5 # 5
        # #, wrap=tk.WORD
        # scr = scrolledtext.ScrolledText(self.monty, width=scrolW, height=scrolH, wrap=tk.WORD) # 6
        # scr.grid(column=0, columnspan=3,sticky=tk.EW,padx=20) # 7,sticky='WE'
        # # scr.grid(column=0, columnspan=3,sticky=tk.EW,padx=20,pady=100,ipady=0)
        # createToolTip(scr, 'This is a ScrolledText widget.')

        # Create a container to hold labels
        labelsFrame = ttk.LabelFrame(self.monty1, text=' Labels in a Frame ') # 1
        labelsFrame.grid(column=1, row=4,padx=6,pady=6)

        # Place labels into the container element # 2
        ttk.Label(labelsFrame, text="Label1").grid(column=0, row=0)
        ttk.Label(labelsFrame, text="Label2").grid(column=0, row=1)
        ttk.Label(labelsFrame, text="Label3").grid(column=0, row=2)

        for child in labelsFrame.winfo_children(): 
            child.grid_configure(padx=8, pady=4)    

        menuBar = Menu(self) # 1------------开辟菜单并生成对象
        self.config(menu=menuBar)#----------配置生效
        #menuBar.add_command(label="233")
        def _quit():
            self.win.quit()
            self.win.destroy()
            exit()

        fileMenu = Menu(menuBar, tearoff=0) # 2----开辟生成按键菜单对象
        fileMenu.add_command(label="New1")#配置按键菜单对象内容
        fileMenu.add_separator()
        fileMenu.add_command(label="Exit",command=_quit)#配置按键菜单对象内容

        menuBar.add_separator()#设置间隔分隔
        menuBar.add_cascade(label="File", menu=fileMenu)#将生成的按键菜单对象应用到菜单栏对象上
        menuBar.add_separator()#设置间隔分隔

        def _msgBox():
            #mBox.showinfo('Python Message Info Box', 'A Python GUI created by 硬菜 using tkinter:\nThe year is 2021.') 
            # mBox.showwarning('Python Message Warning Box', 'A Python GUI created by 硬菜 using tkinter:\nWarning: There might be a bug in this code.')
            # mBox.showerror('Python Message Error Box', 'A Python GUI created by 硬菜 using tkinter:\nError: Houston ~ we DO have a serious PROBLEM!')
            answer = mBox.askyesno("Python Message Dual Choice Box", "Are you sure you really wish to do this?")
            print(answer)
        # Add another Menu to the Menu Bar and an item
        # Display a Message Box
        # Callback function
        helpMenu = Menu(menuBar, tearoff=0) # 6
        helpMenu.add_command(label="About", command=_msgBox)
        menuBar.add_cascade(label="Help", menu=helpMenu)#将生成的按键菜单对象应用到菜单栏对象上

        tabControl.pack(expand=1, fill="both") # Pack to make visible



        self.status_frame = tk.LabelFrame(self, text="系统状态")
        self.status_frame.pack(padx=10, pady=5, fill=tk.BOTH, expand=True)
        # self.status_frame.pack(padx=10, pady=5, fill=tk.X, ipady=10)  # ipady=10 减少内部可用高度


        self.motor_label = tk.Label(
            self.status_frame, 
            text="电机状态: 等待启动...",
            anchor="w"
        )
        self.motor_label.pack(fill=tk.X, padx=5, pady=2)

        self.sensor_label = tk.Label(
            self.status_frame, 
            text="传感器状态: 等待启动...",
            anchor="w"
        )
        self.sensor_label.pack(fill=tk.X, padx=5, pady=2)
        # 日志区域
        self.log_text = tk.Text(self, height=2)
        self.log_text.pack(padx=10, pady=5, fill=tk.BOTH, expand=True)
        self.log_text.insert(tk.END, "系统启动...\n")
        # 关闭按钮
        self.btn_stop = tk.Button(
            self, 
            text="安全关闭系统", 
            command=self.safe_shutdown,
            bg="#ff9999"
        )
        self.btn_stop.pack(pady=10)

    
    def start_workers(self):
        """启动传感器线程（电机线程已在 MotorController 实例化时启动）"""
        self.sensor_thread = ProximitySensor(self.stop_event_sensor, self.status_queue)
        self.sensor_thread.daemon = True
        self.sensor_thread.start()
    
    def update_ui(self):
        # 处理所有待更新的状态
        while not self.status_queue.empty():
            try:
                source, message = self.status_queue.get_nowait()
                if source == "motor":
                    self.motor_label.config(text=f"电机状态: {message}")
                elif source == "sensor":
                    self.sensor_label.config(text=f"传感器状态: {message}")
                
                # 添加到日志
                self.log_text.insert(tk.END, f"{message}\n")
                self.log_text.see(tk.END)
            except queue.Empty:
                break
        
        # 检查线程状态
        # if not self.motor_thread.is_alive() and not self.sensor_thread.is_alive():
        #     self.log_text.insert(tk.END, "所有工作线程已安全退出\n")
        #     self.btn_stop.config(state=tk.DISABLED)
        #     return
        if not self.sensor_thread.is_alive():
            self.log_text.insert(tk.END, "sensor线程已安全退出\n")
            self.btn_stop.config(state=tk.DISABLED)
            return

        # 继续定期检查
        self.after(200, self.update_ui)
    
    def safe_shutdown(self):
        logging.info("接收到关闭信号")

        if hasattr(self, 'motor'):
            self.motor.release()   # 释放 GPIO 引脚

        self.stop_event.set()  # 通知电机线程停止
        self.stop_event_sensor.set()  # 通知传感器线程停止工作
        
        # 禁用关闭按钮防止重复点击
        self.btn_stop.config(state=tk.DISABLED, text="正在关闭...")
        self.log_text.insert(tk.END, "正在停止工作线程...\n")
        
        # 等待线程结束（非阻塞方式）
        self.after(100, self.check_threads)
    
    def check_threads(self):
        # 检查线程是否已停止
        if not hasattr(self, 'motor_thread') or not hasattr(self, 'sensor_thread'):
            self.log_text.insert(tk.END, "线程对象不存在，直接退出界面\n")
            self.destroy()
            return
            
        if self.motor_thread.is_alive() or self.sensor_thread.is_alive():
            self.after(200, self.check_threads)
        else:
            self.log_text.insert(tk.END, "系统可以安全关闭\n")
            self.destroy()  # 关闭Tkinter窗口
    def on_closing(self):
        """窗口关闭时调用的函数"""
        if hasattr(self, 'motor'):
            self.motor.stop()      # 停止电机
            self.motor.release()   # 释放 GPIO 引脚
        self.root.destroy()        # 关闭窗口    
    # def mainloop(self):
    #     self.mainloop()

    def safe_pause_motor(self):
        """安全停止电机，不影响其他线程"""
        self.motor.pause()
